#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import http.server
import socketserver
import json
import urllib.parse
from urllib.parse import urlparse, parse_qs
import webbrowser
import os
import requests
from datetime import datetime, timedelta

# 新增导入：铁路API与DeepSeek
try:
    from simple_railway_api import RailwayAPI
except Exception:
    RailwayAPI = None

try:
    from api_keys_complete import DEEPSEEK_API_KEY, DEEPSEEK_BASE_URL, DEEPSEEK_MODEL
except Exception:
    DEEPSEEK_API_KEY, DEEPSEEK_BASE_URL, DEEPSEEK_MODEL = None, None, None

# 聚合数据配置
try:
    from api_keys_complete import JUHE_TRAIN_APPKEY, JUHE_TRAIN_ENABLED
    from api_keys_complete import JUHE_FLIGHT_APPKEY, JUHE_FLIGHT_ENABLED, JUHE_FLIGHT_MAX_SEGMENTS
except Exception:
    JUHE_TRAIN_APPKEY, JUHE_TRAIN_ENABLED = None, False
    JUHE_FLIGHT_APPKEY, JUHE_FLIGHT_ENABLED, JUHE_FLIGHT_MAX_SEGMENTS = None, False, 1

# 高德API
try:
    from backend.gaode_api import GaodeAPI
except Exception:
    GaodeAPI = None

try:
    from api_keys_complete import GAODE_API_KEY as GAODE_KEY
except Exception:
    try:
        from api_keys import GAODE_API_KEY as GAODE_KEY
    except Exception:
        GAODE_KEY = None

# 可选：使用openai官方客户端兼容DeepSeek
try:
    import openai
    OpenAIClient = openai.OpenAI  # 兼容openai>=1.0.0
except Exception:
    OpenAIClient = None

# 初始化铁路API与高德API实例
_railway_api = RailwayAPI() if RailwayAPI else None
_gaode_api = GaodeAPI(GAODE_KEY) if (GaodeAPI and GAODE_KEY) else None

# 聚合数据客户端
try:
    from backend.train_api import TrainJuheClient, FlightJuheClient
    _juhe_client = TrainJuheClient(JUHE_TRAIN_APPKEY) if (JUHE_TRAIN_ENABLED and JUHE_TRAIN_APPKEY) else None
    _juhe_flight_client = FlightJuheClient(JUHE_FLIGHT_APPKEY, JUHE_FLIGHT_MAX_SEGMENTS) if (JUHE_FLIGHT_ENABLED and JUHE_FLIGHT_APPKEY) else None
except Exception:
    _juhe_client = None
    _juhe_flight_client = None

class MyHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
    def do_GET(self):
        # 将根路径映射到前端页面
        if self.path in ['/', '/index', '/index.html']:
            self.path = '/frontend/index.html'
        elif self.path == '/favicon.ico':
            # 可选：忽略favicon 404
            return self.send_error(404)
        if self.path.startswith('/api/'):
            self.handle_api_request()
        else:
            super().do_GET()
    
    def do_POST(self):
        if self.path.startswith('/api/'):
            self.handle_api_post()
        else:
            super().do_POST()
    
    def do_OPTIONS(self):
        # 处理CORS预检请求
        self.send_response(200)
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
        self.send_header('Access-Control-Allow-Headers', 'Content-Type')
        self.send_header('Access-Control-Max-Age', '86400')
        self.end_headers()
    
    def handle_api_request(self):
        if self.path == '/api/cities':
            self.send_cities()
        elif self.path == '/api/test':
            self.send_test()
        elif self.path == '/api/status':
            self.send_status()
        elif self.path.startswith('/api/weather'):
            # 支持GET weather?city=xxx
            self.send_weather()
        else:
            self.send_error(404)
    
    def handle_api_post(self):
        content_length = int(self.headers.get('Content-Length', 0) or 0)
        post_data = self.rfile.read(content_length) if content_length > 0 else b'{}'
        
        try:
            data = json.loads(post_data.decode('utf-8') or '{}')
            if self.path == '/api/search':
                self.send_search_result(data)
            elif self.path == '/api/chat':
                self.send_chat_response(data)
            elif self.path == '/api/poi':
                self.send_poi(data)
            elif self.path == '/api/geocode':
                self.send_geocode(data)
            elif self.path == '/api/weather':
                # 允许POST方式
                self.send_weather(data)
            else:
                self.send_error(404)
        except Exception as e:
            # 始终返回JSON，避免前端解析失败
            self.send_json_response({'success': False, 'error': f'请求解析失败: {e}'})
    
    def send_cities(self):
        cities = [
            '北京', '上海', '广州', '深圳', '南京', '杭州',
            '成都', '武汉', '西安', '重庆', '天津', '苏州'
        ]
        response = {
            'success': True,
            'cities': [{'id': i + 1, 'name': c, 'code': '', 'level': 'city'} for i, c in enumerate(cities)]
        }
        self.send_json_response(response)
    
    def send_test(self):
        response = {
            'success': True,
            'message': '简单HTTP服务器正常运行！'
        }
        self.send_json_response(response)
    
    def send_status(self):
        response = {
            'success': True,
            'status': 'online',
            'version': '1.0.0',
            'apis': {
                'gaode': 'available' if _gaode_api else 'mock',
                'railway': 'available' if _railway_api else 'mock',
                'ai': 'available' if (DEEPSEEK_API_KEY and DEEPSEEK_BASE_URL and DEEPSEEK_MODEL) else 'mock',
                'juhe_train': 'enabled' if _juhe_client else 'disabled',
                'juhe_flight': 'enabled' if _juhe_flight_client else 'disabled'
            }
        }
        self.send_json_response(response)
    
    # ---------- 智能打分与标签 ----------
    def _score_plan(self, plan):
        price = plan.get('total_price') or 0
        time_h = plan.get('total_time') or 0
        transfers = plan.get('transfers') or 0
        tags = plan.get('tags', [])
        
        # 基础分数
        base_score = 100
        
        # 价格因子（非线性，低价更优）
        if price > 0:
            if price < 300:
                price_factor = price * 0.005  # 低价优惠
            elif price < 600:
                price_factor = price * 0.01   # 中等价格
            else:
                price_factor = price * 0.02   # 高价惩罚
        else:
            price_factor = 50  # 无价格信息惩罚
        
        # 时间因子（非线性，短时间更优）
        if time_h > 0:
            if time_h < 3:
                time_factor = time_h * 1      # 短时间
            elif time_h < 8:
                time_factor = time_h * 2      # 中等时间
            else:
                time_factor = time_h * 4      # 长时间惩罚
        else:
            time_factor = 30  # 无时间信息惩罚
        
        # 换乘因子
        transfer_factor = transfers * 15
        
        # 交通方式加成
        mode_bonus = 0
        if '飞机' in tags and '直达' in tags:
            mode_bonus = 10  # 直达航班加分
        elif '高铁' in tags and '直达' in tags:
            mode_bonus = 5   # 直达高铁加分
        elif '周边出发' in tags or '周边到达' in tags:
            mode_bonus = -5  # 周边城市减分（需额外交通）
        
        # 计算最终分数
        score = base_score - price_factor - time_factor - transfer_factor + mode_bonus
        
        # 确保分数在合理范围内
        score = max(0, min(100, score))
        
        return round(score, 2)
    
    def _build_recommendation(self, plan, constraints):
        reasons = []
        level = 'neutral'
        price = plan.get('total_price') or 0
        time_h = plan.get('total_time') or 0
        transfers = plan.get('transfers') or 0
        tags = plan.get('tags', [])
        
        # 智能推荐逻辑
        is_flight = '飞机' in tags
        is_train = '高铁' in tags or '火车' in tags
        is_nearby = '周边出发' in tags or '周边到达' in tags
        is_direct = '直达' in tags
        
        # 时间窗口检查
        earliest = constraints.get('earliest_time')
        latest = constraints.get('latest_time')
        first_leg = (plan.get('details') or [{}])[0]
        dep_time = first_leg.get('departure_time')
        if dep_time and (earliest or latest):
            try:
                dt = datetime.strptime(dep_time, '%H:%M') if len(dep_time) == 5 else datetime.strptime(dep_time, '%Y-%m-%d %H:%M')
                if earliest:
                    t0 = datetime.strptime(earliest, '%H:%M')
                    if dt.time() < t0.time():
                        reasons.append('出发过早')
                if latest:
                    t1 = datetime.strptime(latest, '%H:%M')
                    if dt.time() > t1.time():
                        reasons.append('出发过晚')
            except Exception:
                pass
        
        # 智能推荐规则
        if is_flight and is_direct and price < 500:
            level = 'highly_recommended'
            reasons.append('直达航班价格优惠')
        elif is_flight and is_nearby and price < 400:
            level = 'recommended'
            reasons.append('周边城市航班价格更低')
        elif is_train and is_direct and time_h < 8:
            level = 'recommended'
            reasons.append('高铁直达便捷')
        elif is_flight and transfers > 0:
            level = 'not_recommended'
            reasons.append('需中转换乘')
        elif is_nearby:
            level = 'neutral'
            reasons.append('需额外交通接驳')
        
        # 价格和时间阈值
        if price and price > 1000:
            reasons.append('价格较高')
        elif price and price < 300:
            reasons.append('价格优惠')
            
        if time_h and time_h > 12:
            reasons.append('时长较长')
        elif time_h and time_h < 3:
            reasons.append('时间较短')
            
        # 最终推荐等级
        if level == 'neutral':
            if not reasons or all('优惠' in r or '便捷' in r or '较短' in r for r in reasons):
                level = 'recommended'
            elif any('较高' in r or '较长' in r or '换乘' in r for r in reasons):
                level = 'not_recommended'
        
        return {'level': level, 'reasons': reasons}
    
    # ---------- 搜索主流程 ----------
    def send_search_result(self, data):
        origin = data.get('origin', '北京')
        destination = data.get('destination', '上海')
        date = data.get('date') or data.get('departure_date')  # YYYY-MM-DD
        optimization_type = data.get('optimization_type', 'time')
        constraints = data.get('constraints', {})
        
        routes = []
        source = 'mock'
        
        # 1) 聚合列车
        if _juhe_client:
            try:
                trains = _juhe_client.query(origin, destination, date or datetime.now().strftime('%Y-%m-%d'))
                for t in trains[:5]:
                    duration = self._parse_duration_to_hours(t.get('duration')) or 0
                    price = t.get('price') or 0
                    plan = {
                        'total_time': duration,
                        'total_price': price,
                        'transfers': 0,
                        'tags': ['直达', '高铁'] if t.get('type') == 'high_speed_rail' else ['直达', '火车'],
                        'details': [
                            {
                                'type': 'high_speed_rail',
                                'origin': t.get('origin') or origin,
                                'destination': t.get('destination') or destination,
                                'departure_time': t.get('departure_time'),
                                'arrival_time': t.get('arrival_time'),
                                'price': price,
                                'train_number': t.get('train_number')
                            }
                        ]
                    }
                    plan['score'] = self._score_plan(plan)
                    plan['recommendation'] = self._build_recommendation(plan, constraints)
                    routes.append(plan)
                source = 'juhe_train'
            except Exception:
                pass
        
        # 2) 12306 解析作为备份
        if not routes and _railway_api:
            try:
                trains = _railway_api.get_train_info(origin, destination, date)
                for t in trains[:5]:
                    duration = self._parse_duration_to_hours(t.get('duration')) or 0
                    price = t.get('price') or 0
                    plan = {
                        'total_time': duration,
                        'total_price': price,
                        'transfers': 0,
                        'tags': ['直达', '高铁'],
                        'details': [
                            {
                                'type': 'high_speed_rail',
                                'origin': t.get('origin') or origin,
                                'destination': t.get('destination') or destination,
                                'departure_time': t.get('departure_time'),
                                'arrival_time': t.get('arrival_time'),
                                'price': price,
                                'train_number': t.get('train_number')
                            }
                        ]
                    }
                    plan['score'] = self._score_plan(plan)
                    plan['recommendation'] = self._build_recommendation(plan, constraints)
                    routes.append(plan)
                source = 'railway'
            except Exception:
                pass
        
        # 3) 航班查询（开启时）
        if _juhe_flight_client:
            try:
                flight_date = date or datetime.now().strftime('%Y-%m-%d')
                
                # 城市名到IATA代码映射
                city_to_iata = {
                    '大连': 'DLC', '北京': 'PEK', '上海': 'PVG', '广州': 'CAN',
                    '深圳': 'SZX', '成都': 'CTU', '重庆': 'CKG', '西安': 'XIY',
                    '武汉': 'WUH', '南京': 'NKG', '杭州': 'HGH', '天津': 'TSN',
                    '青岛': 'TAO', '厦门': 'XMN', '长沙': 'CSX', '郑州': 'CGO',
                    '合肥': 'HFE', '济南': 'TNA', '福州': 'FOC', '南昌': 'KHN',
                    '石家庄': 'SJW', '太原': 'TYN', '呼和浩特': 'HET', '沈阳': 'SHE',
                    '长春': 'CGQ', '哈尔滨': 'HRB', '昆明': 'KMG', '贵阳': 'KWE',
                    '南宁': 'NNG', '海口': 'HAK', '三亚': 'SYX', '兰州': 'LHW',
                    '西宁': 'XNN', '银川': 'INC', '乌鲁木齐': 'URC', '拉萨': 'LXA'
                }
                
                # 获取IATA代码
                dep_code = data.get('departure_iata') or city_to_iata.get(origin, origin)
                arr_code = data.get('arrival_iata') or city_to_iata.get(destination, destination)
                
                # 主要航班查询
                flights = _juhe_flight_client.query(dep_code, arr_code, flight_date)
                
                # 智能扩展：周边城市航班查询
                nearby_cities = {
                    '大连': ['沈阳', '青岛', '天津'],
                    '合肥': ['南京', '上海', '武汉', '杭州'],
                    '北京': ['天津', '石家庄'],
                    '上海': ['南京', '杭州', '无锡'],
                    '广州': ['深圳', '珠海'],
                    '深圳': ['广州', '香港']
                }
                
                # 如果主要航班查询结果较少，尝试周边城市
                if len(flights) < 3:
                    origin_nearby = nearby_cities.get(origin, [])
                    dest_nearby = nearby_cities.get(destination, [])
                    
                    # 查询出发地周边城市到目的地的航班
                    for nearby_origin in origin_nearby[:2]:
                        nearby_dep_code = city_to_iata.get(nearby_origin)
                        if nearby_dep_code:
                            nearby_flights = _juhe_flight_client.query(nearby_dep_code, arr_code, flight_date)
                            for f in nearby_flights[:2]:
                                f['origin_city'] = nearby_origin  # 标记实际出发城市
                                f['transfer_type'] = 'nearby_departure'  # 标记为周边出发
                                flights.append(f)
                    
                    # 查询出发地到目的地周边城市的航班
                    for nearby_dest in dest_nearby[:2]:
                        nearby_arr_code = city_to_iata.get(nearby_dest)
                        if nearby_arr_code:
                            nearby_flights = _juhe_flight_client.query(dep_code, nearby_arr_code, flight_date)
                            for f in nearby_flights[:2]:
                                f['destination_city'] = nearby_dest  # 标记实际到达城市
                                f['transfer_type'] = 'nearby_arrival'  # 标记为周边到达
                                flights.append(f)
                for f in flights[:8]:  # 增加显示数量
                    # 估算总时长
                    duration = self._parse_duration_to_hours(f.get('duration')) or 0
                    price = f.get('price') or 0
                    
                    # 智能标签生成
                    tags = []
                    if f.get('transfer_type') == 'nearby_departure':
                        tags.extend(['周边出发', '飞机'])
                        # 添加高铁接驳信息
                        tags.append('需高铁接驳')
                    elif f.get('transfer_type') == 'nearby_arrival':
                        tags.extend(['周边到达', '飞机'])
                        # 添加高铁接驳信息
                        tags.append('需高铁接驳')
                    elif len(f.get('segments') or []) > 0:
                        tags.extend(['中转', '飞机'])
                    else:
                        tags.extend(['直达', '飞机'])
                    
                    plan = {
                        'total_time': duration,
                        'total_price': price,
                        'transfers': (len(f.get('segments') or []) > 0) or (f.get('transfer_type') is not None),
                        'tags': tags,
                        'details': [
                            {
                                'type': 'flight',
                                'origin': f.get('origin_city') or f.get('origin'),
                                'destination': f.get('destination_city') or f.get('destination'),
                                'departure_time': (f.get('departure_time') or '')[-5:],
                                'arrival_time': (f.get('arrival_time') or '')[-5:],
                                'price': price,
                                'flight_number': f.get('flight_number'),
                                'transfer_info': f.get('transfer_type'),
                                'description': self._get_flight_description(f)
                            }
                        ]
                    }
                    plan['score'] = self._score_plan(plan)
                    plan['recommendation'] = self._build_recommendation(plan, constraints)
                    routes.append(plan)
                if flights:
                    source += '+juhe_flight' if source != 'mock' else 'juhe_flight'
            except Exception:
                pass
        
        # 4) 排序（系统推荐：按 score）
        routes.sort(key=lambda x: x.get('score', 0), reverse=True)
        
        response = {
            'success': True,
            'routes': routes,
            'message': f'为您找到 {len(routes)} 条路线',
            'source': source,
            'params': {
                'origin': origin,
                'destination': destination,
                'date': date,
                'optimization_type': optimization_type
            }
        }
        self.send_json_response(response)
    
    def _get_flight_description(self, flight_data):
        """生成航班描述信息"""
        transfer_type = flight_data.get('transfer_type')
        if transfer_type == 'nearby_departure':
            origin_city = flight_data.get('origin_city')
            return f'从{origin_city}出发，需先乘坐高铁到大连'
        elif transfer_type == 'nearby_arrival':
            dest_city = flight_data.get('destination_city')
            return f'到达{dest_city}，需再乘坐高铁到合肥'
        elif len(flight_data.get('segments', [])) > 0:
            return '中转航班，需在途中换乘'
        else:
            return '直达航班，无需换乘'
    
    def _parse_duration_to_hours(self, duration_text):
        try:
            text = str(duration_text)
            if '小时' in text or '分' in text:
                hours = 0.0
                if '小时' in text:
                    h_part = text.split('小时')[0]
                    hours += float(h_part)
                    text = text.split('小时')[1]
                if '分' in text:
                    m_part = text.split('分')[0]
                    minutes = float(m_part)
                    hours += minutes / 60.0
                return round(hours, 2)
            if ':' in text:
                hh, mm = text.split(':')[:2]
                return round(int(hh) + int(mm) / 60.0, 2)
            if text.replace('.', '', 1).isdigit():
                return float(text)
        except Exception:
            pass
        return None

    def _format_now(self, tz_offset_minutes=None):
        # JS: getTimezoneOffset 返回“本地到UTC的差值(分钟)”，本地 = UTC - offset
        if tz_offset_minutes is None:
            return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        try:
            local_time = datetime.utcnow() - timedelta(minutes=int(tz_offset_minutes))
            return local_time.strftime('%Y-%m-%d %H:%M:%S')
        except Exception:
            return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    
    def _is_time_query(self, text: str) -> bool:
        if not text:
            return False
        keywords = ['现在几点', '几点了', '几点', '时间', '日期', '今天几号', '几月几号', '今天星期', '星期几', '今天是几号']
        return any(k in text for k in keywords)
    
    def _deepseek_chat(self, message, tz_offset_minutes=None):
        # 组装系统提示，注入服务器和用户本地时间
        server_now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        user_now = self._format_now(tz_offset_minutes)
        system_prompt = (
            f"你是一个旅行助手，请用简洁的中文回复。"
            f"当前服务器时间：{server_now}；用户本地时间：{user_now}。"
            f"回答涉及‘现在/今天/几点/日期/星期’等时间问题时，请以用户本地时间为准。"
        )
        # 优先使用openai客户端连接DeepSeek官方兼容端点
        if DEEPSEEK_API_KEY and DEEPSEEK_BASE_URL and DEEPSEEK_MODEL and OpenAIClient:
            try:
                client = OpenAIClient(api_key=DEEPSEEK_API_KEY, base_url=DEEPSEEK_BASE_URL)
                resp = client.chat.completions.create(
                    model=DEEPSEEK_MODEL,
                    messages=[
                        {"role": "system", "content": system_prompt},
                        {"role": "user", "content": message}
                    ],
                    max_tokens=300,
                    temperature=0.7
                )
                return {
                    'success': True,
                    'response': resp.choices[0].message.content
                }
            except Exception as e:
                # 降级到HTTP直连
                pass
        
        # 兜底：HTTP直连DeepSeek（无需openai库）
        if DEEPSEEK_API_KEY and DEEPSEEK_BASE_URL and DEEPSEEK_MODEL:
            try:
                url = f"{DEEPSEEK_BASE_URL.rstrip('/')}/chat/completions"
                headers = {
                    'Authorization': f'Bearer {DEEPSEEK_API_KEY}',
                    'Content-Type': 'application/json'
                }
                payload = {
                    'model': DEEPSEEK_MODEL,
                    'messages': [
                        {"role": "system", "content": system_prompt},
                        {"role": "user", "content": message}
                    ],
                    'max_tokens': 300,
                    'temperature': 0.7
                }
                r = requests.post(url, headers=headers, json=payload, timeout=15)
                j = r.json()
                if 'choices' in j and j['choices']:
                    content = j['choices'][0].get('message', {}).get('content', '')
                    if content:
                        return {'success': True, 'response': content}
                # 返回错误信息
                return {'success': False, 'error': f'DeepSeek HTTP错误: {j}'}
            except Exception as e:
                return {'success': False, 'error': f'DeepSeek直连失败: {e}'}
        
        return {'success': False, 'error': 'DeepSeek未配置或依赖缺失'}
    
    def send_chat_response(self, data):
        message = data.get('message', '')
        if not message:
            self.send_json_response({'success': False, 'error': '请提供message'})
            return
        
        tz_offset = data.get('timezoneOffsetMinutes') or data.get('timezone_offset')
        
        # 本地时间问题优先用用户本地时间直接回答
        if self._is_time_query(message):
            now_text = self._format_now(tz_offset)
            self.send_json_response({'success': True, 'response': f'现在是 {now_text}（您的本地时间）', 'model': 'builtin'})
            return
        
        # 先调用DeepSeek，失败则返回简单模拟
        ds = self._deepseek_chat(message, tz_offset_minutes=tz_offset)
        if ds.get('success'):
            response = {
                'success': True,
                'response': ds['response'],
                'intent': {
                    'type': 'unknown',
                    'origin': None,
                    'destination': None
                },
                'model': 'DeepSeek'
            }
            self.send_json_response(response)
            return
        
        # 回退模拟
        response = {
            'success': True,
            'response': f'我收到了您的消息："{message}"。这是一个模拟回复。',
            'intent': {
                'type': 'unknown',
                'origin': None,
                'destination': None
            },
            'model': 'mock',
            'error': ds.get('error')
        }
        self.send_json_response(response)
    
    def send_poi(self, data):
        keyword = data.get('keyword', '景点')
        city = data.get('city', '')
        types = data.get('types', '')
        
        # 优先高德封装
        if _gaode_api:
            try:
                pois_raw = _gaode_api.search_poi(keyword, city or None)
                if pois_raw:
                    pois = []
                    for p in pois_raw[:8]:
                        pois.append({
                            'id': p.get('id', ''),
                            'name': p.get('name', ''),
                            'type': p.get('type', ''),
                            'address': p.get('address', ''),
                            'location': p.get('location', '')
                        })
                    self.send_json_response({'success': True, 'pois': pois})
                    return
            except Exception:
                pass
        
        # 直连高德 place/text
        if GAODE_KEY:
            try:
                url = 'https://restapi.amap.com/v3/place/text'
                params = {
                    'key': GAODE_KEY,
                    'keywords': keyword,
                    'output': 'json',
                    'extensions': 'all'
                }
                if city:
                    params['city'] = city
                if types:
                    params['types'] = types
                r = requests.get(url, params=params, timeout=8)
                dj = r.json()
                if dj.get('status') == '1' and dj.get('pois'):
                    pois = []
                    for p in dj['pois'][:8]:
                        pois.append({
                            'id': p.get('id', ''),
                            'name': p.get('name', ''),
                            'type': p.get('type', ''),
                            'address': p.get('address', p.get('adname', '')),
                            'location': p.get('location', '')
                        })
                    self.send_json_response({'success': True, 'pois': pois})
                    return
            except Exception:
                pass
        
        # 回退示例（仅当真实API不可用时）
        pois = []
        for i in range(3):
            pois.append({
                'id': str(i + 1),
                'name': f'{(city or "北京")}{keyword}{i + 1}',
                'type': keyword,
                'address': f'{(city or "北京")}示例地址{i + 1}',
                'location': f'116.39{i}{i},39.90{i}{i}'
            })
        self.send_json_response({'success': True, 'pois': pois})
    
    def send_geocode(self, data):
        address = data.get('address', '')
        # 优先高德封装
        if _gaode_api and address:
            try:
                loc = _gaode_api.geocode(address)
                if loc:
                    lng, lat = loc
                    self.send_json_response({
                        'success': True,
                        'coordinates': {'lng': lng, 'lat': lat},
                        'address': address
                    })
                    return
            except Exception:
                pass
        # 直连一次
        if GAODE_KEY and address:
            try:
                url = 'https://restapi.amap.com/v3/geocode/geo'
                r = requests.get(url, params={'key': GAODE_KEY, 'address': address, 'output': 'json'}, timeout=8)
                dj = r.json()
                if dj.get('status') == '1' and dj.get('geocodes'):
                    loc = dj['geocodes'][0].get('location', '')
                    if loc and ',' in loc:
                        lng, lat = [float(x) for x in loc.split(',')]
                        self.send_json_response({'success': True,'coordinates': {'lng': lng, 'lat': lat},'address': address})
                        return
            except Exception:
                pass
        # 回退固定坐标
        self.send_json_response({
            'success': True,
            'coordinates': {'lng': 116.3974, 'lat': 39.9093},
            'address': address
        })
    
    def send_json_response(self, data):
        self.send_response(200)
        self.send_header('Content-type', 'application/json; charset=utf-8')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
        self.send_header('Access-Control-Allow-Headers', 'Content-Type')
        self.end_headers()
        
        json_data = json.dumps(data, ensure_ascii=False, indent=2)
        self.wfile.write(json_data.encode('utf-8'))

if __name__ == '__main__':
    PORT = 5000
    
    print("=" * 60)
    print("启动简单HTTP服务器")
    print("=" * 60)
    print(f"服务地址: http://localhost:{PORT}")
    print(f"测试地址: http://localhost:{PORT}/api/test")
    print(f"城市列表: http://localhost:{PORT}/api/cities")
    print(f"前端页面: http://localhost:{PORT}/frontend/index.html")
    print("=" * 60)
    print("按 Ctrl+C 停止服务")
    print("=" * 60)
    
    try:
        # 自动打开浏览器到前端页面
        try:
            webbrowser.open(f"http://localhost:{PORT}/frontend/index.html")
        except Exception:
            pass
        with socketserver.TCPServer(("", PORT), MyHTTPRequestHandler) as httpd:
            httpd.serve_forever()
    except KeyboardInterrupt:
        print("\n服务器已停止")
    except Exception as e:
        print(f"服务器启动失败: {e}")